package cc.eddic.practice.concurrency;

import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.Collection;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
@SpringBootApplication
public class ConcurrencyGcsApplication implements CommandLineRunner {
    public static void main(String[] args) {
        SpringApplication.run(ConcurrencyGcsApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
//        elapse("loop", this::loop);
//        elapse("executor", this::executor);

        elapse(LOG_PARSER_IMPL, this::logParse);
    }

    private static final String LOG_PARSER_IMPL = "LogParserWithFutureImpl";

    private void elapse(String taskName, Runnable runnable) {
        long start = System.currentTimeMillis();
        log.info("{} start", taskName);

        try {
            runnable.run();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        log.info("{} elapsed {} ms", taskName, System.currentTimeMillis() - start);
    }

    private void executor() {
        ExecutorService executorService = Executors.newFixedThreadPool(32);
        CountDownLatch latch = new CountDownLatch(LOG_FILE_COUNT);

        if (log.isInfoEnabled()) log.info("submit {} tasks", LOG_FILE_COUNT);
        for (int i = 0; i < LOG_FILE_COUNT; i++) {
            int finalI = i;
            if (log.isDebugEnabled()) log.debug("submit {}", finalI);
            executorService.submit(() -> dummyParse(finalI, latch));
        }

        if (log.isInfoEnabled()) log.info("latch await");
        try {
            latch.await();
        } catch (InterruptedException e) {
            log.error(e.getMessage());
        }
//        ExecutorServiceUtil.shutdown(executorService);

        if (log.isInfoEnabled()) log.info("shutdown");
        executorService.shutdownNow();
    }

    private void dummyParse(int i, CountDownLatch latch) {
        dummyParse(i);
        latch.countDown();
    }

    private void loop() {
        for (int i = 0; i < LOG_FILE_COUNT; i++) {
            dummyParse(i);
        }
    }

    private void dummyParse(int i) {
        try {
//            val r = rnd(10, 50);
            int r = 10;
            if (log.isDebugEnabled()) log.debug("{}", i);
            Thread.sleep(r);
            if (log.isDebugEnabled()) log.debug("{} => sleep {} ms", i, r);
        } catch (InterruptedException e) {
            log.error(e.getMessage());
        }
    }

    private int rnd(int min, int max) {
        return random.nextInt(max - min + 1) + min;
    }

    private final int LOG_FILE_COUNT = 256;

    private final Random random = new Random(System.currentTimeMillis());

    private void logParse() {
//        val folder = "/Users/gucs/Projects/97-Eddic-SONY/20230809";
//        val folder = "/Users/gucs/Projects/97-Eddic-SONY/20230811/one-file";
        val folder = "/Users/gucs/Projects/97-Eddic-SONY/20230811/2023-04";
//        val folder = "/Users/gucs/Projects/97-Eddic-SONY/20230731";
        val logItems = logParser.parse(folder);
        if (log.isInfoEnabled()) {
            log.info("files : {}", logItems.size());
            log.info("total log items : {}", logItems.values().stream().mapToLong(Collection::size).sum());
            log.info("valid log items : {}", logItems.values().stream().flatMap(Collection::stream).filter(LogItem::isValidRequest).count());

//            logItems.values().stream().flatMap(Collection::stream).filter(x -> !x.isValidRequest()).map(LogItem::getRequest).forEach(System.out::println);
        }
    }

    public ConcurrencyGcsApplication(@Qualifier(LOG_PARSER_IMPL) LogParser logParser) {
        this.logParser = logParser;
    }

    private final LogParser logParser;
}
